#ifndef __qylexerfactory__
#define __qylexerfactory__

#include <QMap>

class QSettings;
class QsciLexer;

/*! \class QyLexerFactory
	\brief Фабрика лексеров.

	QyLexerFactory одновременно является интерфейсом получения лексеров для редакторов по типу файлов и интерфейсом для построения пользовательских фабрик.

	Для начала рассмотрим QyLexerFactory как интерфейс получения лексеров.
	Принцип работы фабрики проще всего показать на приере с текстовым редактором:
	Допустим у нас есть задача - всякий раз "загружая файл в редактор", нам необходимо получать лексер соответствующий типу файла. Для этого существует статический метод QyLexerFactory::lexer, который по имени файла (вернее по типу извлекаемому из имени, т.е. расширению) возвращает нужный лексер.

	\code
	void openFileInEditor( QsciScintilla * edit, const QString & fileName ) {

		... // загрузка содержимого файла в редактор

		QsciLexer * lexer = QyLexerFactory::lexer(fileName); // получаем лексер по имени файла

		if (lexer)
			edit->setLexer(lexer); // если лексер для данного типа файлов найден, то устанавливаем его для нашего редактора

	}
	\endcode

	Ничего сложного. =)

	Теперь рассмотрим QyLexerFactory как интерфейс построения фабрик.

	Допустим у нас есть лексер, например входящий в состав QScintilla - QsciLexerCPP. Для того чтобы мы могли получить доступ к нему через интерфейс фабрики, нам необходимо создать собственную фабрику, которая будет заниматься менеджментом лексеров данного типа (созданием, удалением и т.д.).

	\code

	class MyCppLexerFactory : public QyLexerFactory {
	public:
		MyCppLexerFactory() : QyLexerFactory("*.cpp;*.h") {
			myCppLexer = new QsciLexerCPP;
		}
		viretual ~MyCppLexerFactory() {
			delete myCppLexer;
		}

		QsciLexer * lexer() const {
			return myCppLexer;
		}

	private:
		QsciLexerCPP * myCppLexer;

	};

	\endcode

	Далее например в функции main нужно создать экземпляр класса MyCppLexerFactory. После чего фабрика регистрируется и деригистрируется внутри "системы" самостоятельно (при ее создании и удалении соответственно).

	В данном случае, наша фабрика создает один единственный экземпляр cpp лексера и будет возвращает его на все запросы. В принципе, для работы этого достаточно (но право создавать новый лексер на каждый запрос - остается за пользователем). Теперь каждый раз, запрашивая лексер для файла с расширением cpp или h, мы будем получать нашь лексер.
	Следует отметить, что если мы создаем фабрику, которая занимается обработкой уже существующего типа файлов, система перемещает "старую" фабрику в список "старых" фабрик, который можно очистить вызовом deleteOldFactories. Это следует делать только если вы уверены что лексеры, созданные "старыми" фабриками больше никто не использует, а также что все фабрики которые могут оказаться в списке "старых" не были созданы в стеке.

	Еще один момент, если например у нас есть фабрика для подсветки "*.cpp;*.h" файлов и фабрика для "*.cpp;*.hpp" (т.е. они обе могут обеспечить подсветку cpp файлов), то при получении лексера, я не берусь предсказать какая из них будет выбрана, все зависит от сортировки значений в QMap.

	Предупреждение: необходимо обеспечить создание пользовательских фабрик после инициализации статических переменных находящихся в глобальной области. Иначе стабильная работа не гарантируется.

*/

class QyLexerFactory {
public:
	QyLexerFactory( const QString & fileFilter ); //!< Конструктор, принимающий список типов файлов для которых будет использоватся лексер(ы) создаваемые данной фабрикой. Регистрирует фабрику.
	virtual ~QyLexerFactory(); //!< Диструктор. Деригистрирует фабрику.

	virtual QString displayName() const; //!< имя лексера для отображения
	// virtual QString nameWithoutSpace() const;
	QString fileFilter() const { return p_fileFilter; } //!< фильтр
	virtual bool match( const QString & fileName ) const; //!< может ли использоваться лексер фабрики для подсветки данного файла
	virtual QsciLexer * lexer() const; //!< получит у фабрики лексер
#ifdef QY_USE_QSETTINGS_FOR_LEXERFACTORY
	virtual void restoreLexerSettings( QSettings & settings, const QString & prefix=QString() );
	virtual void saveLexerSettings( QSettings & settings, const QString & prefix=QString() );
#endif/*QY_USE_QSETTINGS_FOR_LEXERFACTORY*/
	static QList<QyLexerFactory*> factories(); //!< список фабрик
	static QsciLexer * lexer( const QString & fileName ); //!< получить лексер для подсветки данного файла
	static QsciLexer * lexerByFilefilter( const QString & fileFilter ); //!< получить лексер по фильтру (для получения правильного значения, необходимо полное соответствие fileFilter с одним из фильтров зарегестрированных фабрик)
	static bool contains( const QString & fileFilter ) { return p_factories.contains(fileFilter); } //!< существует ли фабрика с таким фильтром
	static void deleteOldFactories(); //!< удалить устаревшие фабрики
	static void clear(); //!< удалить все фабрики и очистить список фабрик
#ifdef QY_USE_QSETTINGS_FOR_LEXERFACTORY
	static void restoreLexersSettings( QSettings & settings, const QString & prefix=QString() );
	static void saveLexersSettings( QSettings & settings, const QString & prefix=QString() );
#endif/*QY_USE_QSETTINGS_FOR_LEXERFACTORY*/

private:
	static QMap<QString,QyLexerFactory*> p_factories;
	static QList<QyLexerFactory*> p_deadFactories;
	static bool p_deleteOldFactories;
	QString p_fileFilter;

};

#endif/*__qylexerfactory__*/
